
#region Imported Namespaces
using System;
using System.Data;
using System.Collections;

using DataAccess = PHSRAG.Utility.DataAccess;
using PHSRAG.Insight21.SearchContext;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.InsightUtilities;
using BO = PHSRAG.Insight21.BusinessObjects;
using PHSRAG.Insight21.Context;
#endregion

namespace PHSRAG.Insight21.Agreements
{
	#region Calss BudgetBreakdowns
	/// <summary>
	/// The BudgetBreakdowns class loads and provides the budget breakdowns based on a specific search criteria.
	/// </summary>
	public class BudgetBreakdowns : BO.BusinessObject
	{
		#region Constants
		private const string FilteredDataTableName = "filtered";
		private const string OriginalDataTableName = "original";
		#endregion

		#region Instance Variables
		private Hashtable		breakdownMap = new Hashtable();
		private int				categoryID;
		private string			currentDataTableName = OriginalDataTableName;
		private string			fundNumber;
		private DateTime		glPostAsOfDate;
		private bool			sortAscending = true;
		private string			sortColumn = "FundNumber";	// Keep this in sync with what the stored proc orders by.
		private decimal			totalBudgetAmount;
		private string			categoryName;
		private string			accountNumber;
		private string			budgetStartDate;
		private string			budgetEndDate;
		#endregion

		#region Constructor
		/// <summary>Set the cache policy in the base class</summary>
		public BudgetBreakdowns() : base(null)
		{
		}
		#endregion

		#region Public Properties
		/// <summary>Get the category ID</summary>
		public int CategoryID { get { return categoryID; } }

		/// <summary>Get the cache key</summary>
		public static string CacheKey { get { return "BudgetBreakdowns_52A49ADC-2B03-459b-A883-31416630F8BF"; } }

		/// <summary>Get the number of items</summary>
		public int Count { get { return DataContainer.Tables[0].Rows.Count; } }

		/// <summary>Get the fund number</summary>
		public string FundNumber { get { return fundNumber; } }

		/// <summary>Get the GL post-as-of date</summary>
		public DateTime GLPostAsOfDate { get { return glPostAsOfDate; } }

		/// <summary>Get the Budget Start date</summary>
		public string BudgetStartDate { get { return (budgetStartDate != null) ? budgetStartDate : string.Empty; } }

		/// <summary>Get the Budget End date</summary>
		public string BudgetEndDate { get { return (budgetEndDate != null) ? budgetEndDate : string.Empty; } }

		/// <summary>Get the predicate indicating sort order</summary>
		public bool SortAscending {	get { return sortAscending; } }
		
		/// <summary>Get the name of the column on which data is sorted</summary>
		public string SortColumn { get { return sortColumn; } }

		/// <summary>Get the total budget amount</summary>
		public decimal TotalBudgetAmount { get { return totalBudgetAmount; } }

		/// <summary>Get the category name</summary>
		public string CategoryName { get { return categoryName; } }

		/// <summary>Get the account number</summary>
		public string AccountNumber { get { return accountNumber; } }
		#endregion

		#region Public Methods
		/// <summary>
		/// </summary>
		/// <param name="startIndex">Index within the agreement summary list to begin at</param>
		/// <param name="count">Total number of agreement objects to load</param>
		/// <returns>The list of agreement objects</returns>
		public ArrayList GetBreakdownList(int startIndex, int count)
		{
			ArrayList breakdownList = breakdownMap[startIndex] as ArrayList;
			if (breakdownList == null)
			{
				breakdownList = new ArrayList();
				DataTable dataTable = DataContainer.Tables[currentDataTableName];
				for (int i = startIndex, end = Math.Min(i + count, dataTable.Rows.Count); i < end; ++i)
					breakdownList.Add(new BudgetBreakdown(dataTable.Rows[i]));
				breakdownMap[startIndex] = breakdownList;
			}
			return breakdownList;
		}

		/// <summary>
		/// </summary>
		/// <param name="searchArgs"></param>
		/// <remarks>True if the search criteria did any filtering; false otherwise</remarks>
		public bool Search(params object[] searchArgs)
		{
			breakdownMap.Clear();
			Load(Utility.DataAccess.ConnectionString, searchArgs);
			return true;
		}

		/// <summary>
		/// Sort the list of agreement summaries by the speicified column.
		/// If the column is to be sorted is the same as what was last sorted on, the sort sequence is toggled. Else, the
		/// sort sequence is set to ascending.
		/// </summary>
		/// <param name="columnName">Column to sort by</param>
		public void Sort(string columnName)
		{
			breakdownMap.Clear();

			sortAscending = (sortColumn == columnName) ? !sortAscending : true;
			sortColumn = columnName;

			DataTable dataTable = DataContainer.Tables[currentDataTableName];
			DataView dataView = dataTable.DefaultView;
			dataView.Sort = string.Format("{0} {1}", columnName, sortAscending ? "ASC" : "DESC");

			DataTable sortedDataTable = dataTable.Clone();
			foreach (DataRowView rowView in dataView)
				sortedDataTable.ImportRow(rowView.Row);

			DataContainer.Tables.Remove(currentDataTableName);
			DataContainer.Tables.Add(sortedDataTable);
		}
		#endregion

		#region BusinessObject Methods
		/// <summary>
		/// Load the data container with budget breakdown data based on the specified search criteria.
		/// </summary>
		/// <param name="connectionString">Connection string to the database</param>
		/// <param name="args">Expected to contain the search criteria</param>
		public override void Load(string connectionString, params object[] args)
		{
			if ((args.Length != 2))
				throw new Exception("Budget breakdown load requires a session Id and search criteria");

			if (!(args[0] is string))
				throw new Exception("Budget breakdown load requires a session Id");

			if (!(args[1] is SearchCriteria))
				throw new Exception("Budget breakdown load requires search criteria");

			string sessionID = (string)args[0];
			SearchCriteria searchCriteria = (SearchCriteria)args[1];
			System.Diagnostics.Trace.WriteLine(string.Format("{0}: SearchCriteria: {1}", DateTime.Now, searchCriteria.ToString()));

			object includeProgramProjects = searchCriteria[Constants.IncludeProgramProjectsKey];
			bool includeDirect = (includeProgramProjects == null) ? false : Convert.ToBoolean(includeProgramProjects);

			DataContainer = DataAccess.GetDataSet(connectionString, "GetBudgetBreakdown",
				DataAccess.BuildSqlParameterArray(
				"@sessionId", SqlDbType.VarChar, sessionID,
				"@domainUserId", SqlDbType.Int, searchCriteria[Constants.DomainUserIDKey],
				"@includeProgramProjects", SqlDbType.Bit, includeDirect,
				"@fundNumber", SqlDbType.VarChar, fundNumber = searchCriteria[Constants.FundIDKey],
				"@folderNumber", SqlDbType.VarChar, searchCriteria[Constants.FolderNumberKey],
				"@bicsNumber", SqlDbType.VarChar, searchCriteria[Constants.BicsNumberKey],
				"@walkerNumber", SqlDbType.VarChar, searchCriteria[Constants.WalkerNumberKey],
				"@sponsorNumber", SqlDbType.VarChar, searchCriteria[Constants.SponsorNumberKey],
				"@sponsorName", SqlDbType.VarChar, searchCriteria[Constants.SponsorNameKey],
				"@sponsorTypeId", SqlDbType.Int, searchCriteria[Constants.SponsorTypeIDKey],
				"@agreementTypeId", SqlDbType.Int, searchCriteria[Constants.AgreementTypeIDKey],
				"@activityCode", SqlDbType.VarChar, searchCriteria[Constants.ActivityCodeKey],
				"@locationId", SqlDbType.Int, searchCriteria[Constants.LocationIDKey],
				"@budgetStartDate", SqlDbType.DateTime, searchCriteria[Constants.BudgetStartDateKey],
				"@budgetEndDate", SqlDbType.DateTime, searchCriteria[Constants.BudgetEndDateKey],
				"@projectStartDate", SqlDbType.DateTime, searchCriteria[Constants.ProjectStartDateKey],
				"@projectEndDate", SqlDbType.DateTime, searchCriteria[Constants.ProjectEndDateKey],
				"@piId", SqlDbType.Int, searchCriteria[Constants.PIIDKey],
				"@chiefCodeList", SqlDbType.VarChar, searchCriteria.COSIds,
				"@sponsorGroupTypeId", SqlDbType.Int, searchCriteria[Constants.ViewingOptionKey],
				"@budgetEndingDays", SqlDbType.Int, searchCriteria[Constants.DaysBudgetEndingKey],
				"@projectEndingDays", SqlDbType.Int, searchCriteria[Constants.DaysProjectEndingKey],
				"@fundCreatedDays", SqlDbType.Int, searchCriteria[Constants.DaysFundCreatedKey],
				"@lowBalance", SqlDbType.Decimal, searchCriteria[Constants.BalanceLessThanKey],
				"@highBalance", SqlDbType.Decimal, searchCriteria[Constants.BalanceGreaterThanKey],
				"@agreementStatusTypeList", SqlDbType.VarChar, searchCriteria[Constants.AgreementStatusIDKey],
				"@fundStatusTypeId", SqlDbType.Int, searchCriteria[Constants.FundStatusIDKey],
				"@categoryId", SqlDbType.Int, categoryID = Convert.ToInt32(searchCriteria[Constants.CategoryIDKey]),
				"@accountNumber", SqlDbType.VarChar, searchCriteria[Constants.AccountNumberKey],
				"@selectedFundNumber", SqlDbType.VarChar, searchCriteria[Constants.FundIDKey],
				"@transactionStartDate", SqlDbType.DateTime, searchCriteria[Constants.TransactionStartDateKey],
				"@transactionEndDate", SqlDbType.DateTime, searchCriteria[Constants.TransactionEndDateKey],
				"@detail", SqlDbType.Bit, searchCriteria[Constants.DetailsKey]!=null ? Convert.ToBoolean(searchCriteria[Constants.DetailsKey]) : false ,
                "@cumulative", SqlDbType.Int, searchCriteria[Constants.CumulativeKey] != null ? Convert.ToInt32(searchCriteria[Constants.CumulativeKey]) : 0,
                "@glPostAsOfDate", SqlDbType.DateTime, glPostAsOfDate = Convert.ToDateTime(searchCriteria[Constants.GLPostAsOfDateKey])
				));

			if ((DataContainer.Tables.Count != 1) || (DataContainer.Tables[0].Rows.Count == 0))
				throw new Exception("No information found. Try again with different search criteria.");

			DataContainer.Tables[0].TableName = OriginalDataTableName;
			totalBudgetAmount = Convert.ToDecimal(DataContainer.Tables[0].Compute("SUM(BudgetAmount)", string.Empty));
			categoryName = DataContainer.Tables[0].Rows[0][Constants.BudgetInfoConstants.CategoryColumnName].ToString();
			accountNumber = (searchCriteria[Constants.AccountNumberKey] == null) 
				? string.Empty : searchCriteria[Constants.AccountNumberKey];
			budgetStartDate = (searchCriteria[Constants.TransactionStartDateKey] == null) 
				? string.Empty : searchCriteria[Constants.TransactionStartDateKey];
			budgetEndDate = (searchCriteria[Constants.TransactionEndDateKey] == null) 
				? string.Empty : searchCriteria[Constants.TransactionEndDateKey];
		}
		#endregion
	}
	#endregion

	#region Class BudgetBreakdown
	/// <summary>
	/// The BudgetBreakdown class provides the facade over a single budget breakdown entry.
	/// </summary>
	public class BudgetBreakdown
	{
		#region Instance Variables
		private DataRow dataRow;
		#endregion

		#region Constructor
		public BudgetBreakdown(DataRow dataRow)
		{
			this.dataRow = dataRow;
		}
		#endregion

		#region Public Properties
		/// <summary>Get the budget end date</summary>
		public string BudgetEndDate { get { return GetSafeDate("BudgetEndDate"); } }

		/// <summary>Get the budget amount</summary>
		public string BudgetAmount { get { return GetSafeDecimal("BudgetAmount"); } }

		/// <summary>Get the budget start date</summary>
		public string BudgetStartDate { get { return GetSafeDate("BudgetStartDate"); } }

		/// <summary>Get the Fund Number</summary>
		public string FundNumber { get { return GetSafeString("FundNumber"); } }

		/// <summary>Get the AgreementSummary PI name</summary>
		public string PIName { get { return GetSafeString("PIName"); } }

		/// <summary>Get the Project end date</summary>
		public string ProjectEndDate { get { return GetSafeDate("ProjectEndDate"); } }

		/// <summary>Get the Project start date</summary>
		public string ProjectStartDate { get { return GetSafeDate("ProjectStartDate"); } }

		/// <summary>Get the AgreementSummary sponsor name</summary>
		public string SponsorName { get { return GetSafeString("SponsorName"); } }

		/// <summary>Get the project title</summary>
		public string Title { get { return GetSafeString("ProjectTitle"); } }
		#endregion

		#region Private Methods
		private string GetSafeDate(string columnName)
		{
			object o = dataRow[columnName];
			return (o == DBNull.Value) ? string.Empty : ((DateTime)o).ToString("MM/dd/yyyy");
		}

		private string GetSafeDecimal(string columnName)
		{
			object o = dataRow[columnName];
			return (o == DBNull.Value) ? string.Empty : o.ToString();
		}

		private string GetSafeString(string columnName)
		{
			object o = dataRow[columnName];
			return (o == DBNull.Value) ? string.Empty : (string)o; 
		}
		#endregion
	}
	#endregion
}

// --- EOF ---
